/*
 * 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙，邂逅框架梦，本文采用木兰宽松许可证第2版]
 * 
 * https://zhiqim.org/project/zhiqim_kit/zhiqim_git.htm
 *
 * ZhiqimGit is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
package org.zhiqim.git.command;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.zhiqim.git.Git;
import org.zhiqim.git.GitCommand;
import org.zhiqim.git.GitConfig;
import org.zhiqim.git.GitWalker;
import org.zhiqim.git.objer.objectid.RevCommit;
import org.zhiqim.git.refer.Ref;
import org.zhiqim.git.refer.RefUpdateResult;
import org.zhiqim.git.refer.RefUpdater;


/**
 * 分枝删除命令
 * http://www.kernel.org/pub/software/scm/git/docs/git-branch.html
 * 
 * @version v1.0.0 @author zhichenggang 2017-3-12 新建与整理
 */
public class BranchDeleteCommand extends GitCommand<List<String>>
{
    private final Set<String> branchNames = new HashSet<String>();
    private boolean force;

    public BranchDeleteCommand(Git git)
    {
        super(git);
    }

    /******************************************************************************/
    //设置参数
    /******************************************************************************/
    
    public BranchDeleteCommand setBranchNames(String... branchnames)
    {
        this.branchNames.clear();
        for (String branch : branchnames)
            this.branchNames.add(branch);
        return this;
    }

    public BranchDeleteCommand setForce(boolean force)
    {
        this.force = force;
        return this;
    }
    
    /******************************************************************************/
    //预处理&执行
    /******************************************************************************/
    
    public List<String> execute() throws Exception
    {
        if (branchNames.isEmpty())
            return new ArrayList<String>(0);
        
        List<String> result = new ArrayList<String>();
        String currentBranch = git.getFullBranch();
        
        RevCommit tip = null;
        if (!force)
        {//非强制删除，要求尝试合并
            tip = git.resolve(HEAD, RevCommit.class);
        }
        
        for (String branchName : branchNames)
        {
            if (branchName == null)
                continue;
            
            Ref brancheRef = git.findRef(branchName);
            if (brancheRef == null)
                continue;
            
            String brancheFullName = brancheRef.getName();
            if (brancheFullName.equals(currentBranch))
                throw new Exception("不允许删除当前操作的分枝：" + branchName);
            
            if (!force)
            {//非强制删除，要求尝试合并
                RevCommit base = git.resolve(branchName, RevCommit.class);
                GitWalker walker = new GitWalker(git);
                if (!walker.isFastward(base, tip))
                {
                    throw new Exception("无法合并要删除的分枝：" + branchName);
                }
            }
            
            //删除到仓库
            RefUpdater update = git.newUpdater(brancheFullName);
            update.setRefLogMessage("删除分枝", false); 
            update.setForceUpdate(true);
            
            RefUpdateResult deleteResult = update.delete();
            if (!isSuccess(deleteResult))
                throw new Exception("删除分枝时异常结果：" + deleteResult.name());
            
            //删除到配置文件
            if (brancheFullName.startsWith(P_REFS_HEADS_))
            {//本地分枝删除
                String shortName = brancheFullName.substring(P_REFS_HEADS_.length());
                GitConfig cfg = git.getConfig();
                cfg.unsetSection(_SECTION_BRANCH_, shortName);
                cfg.save();
            }
            
            //删除成功保存到列表返回
            result.add(brancheFullName);
        }
        
        return result;
    }
    
    /******************************************************************************/
    // 私有方法
    /******************************************************************************/
    
    /** 判断结果是否成功 */
    private boolean isSuccess(RefUpdateResult deleteResult)
    {
        switch (deleteResult)
        {
        case IO_FAILURE:
        case LOCK_FAILURE:
        case REJECTED:
            return false;
        default:
            return true;
        }
    }
}
